import requests
import time
import logging
import json
import random
from threading import Timer
import  threading
from os import path

# 配置 #

# 本地缓存IP 路劲
_local_cache = 'ippool.json'
_local_cache = f"{path.dirname(__file__)}/{_local_cache}"
# 代理ip请求地址
_urls = [
    # 套餐
    "http://api.wandoudl.com/api/ip?\
    app_key=73ede7d2edb77d6a39b7de6ec8d21667&pack=219915&num=3&xy=3&type=2&lb=\r\n&mr=2&area_id=310100",

    # 免费版
    "http://api.wandoudl.com/api/ip?\
    app_key=73ede7d2edb77d6a39b7de6ec8d21667&pack=0&num=3&xy=3&type=2&lb=\r\n&mr=2&area_id=500100",


    # "http://webapi.http.zhimacangku.com/getip?\
    # num=10&type=2&pro=0&city=0&yys=0&port=11&pack=133917&ts=1&ys=0&cs=0&lb=1&sb=0&pb=45&mr=2&regions=310000,340000,350000,370000,440000",
]

# ip到期阈值, 距离到期时间还有以下值时, 视为到期
_expire_threshold = 10

# 中心定时器间隔(秒)
_interval = 2

# ip队列最小ip数
_ip_min_num = 3# 6

# 配置end #


# IP队列
_queue = []


def _on_expire():
    global _ct
    _ct = threading.Timer(_interval, _on_expire)
    _ct.start()
    for ip in _queue:
        ip.remained = ip.remained - _interval
        if ip.remained < 0:
            ip.on_expire()
            _remove(ip)
    # 测试
    # if len(_queue) > 0:
        # _remove(_queue[0])
    if len(_queue) < _ip_min_num:
        _request()


# 中心计时器
_ct = threading.Timer(_interval, _on_expire)


class IP:
    def __init__(self, data):
        expire_time = data.get('expire_time', 1577721600)
        self.expire_time = expire_time
        expire_stamp = int(time.mktime(time.strptime(expire_time, "%Y-%m-%d %H:%M:%S")))
        now = int(time.time())
        # now = 1609994233
        if expire_stamp - 10 <= now:
            raise ValueError("IP已经到期")
        self.remained = expire_stamp - now - _expire_threshold
        if 'proxy' in data:
            self.proxy = data['proxy']
        else:
            self.proxy = f"{data['ip']}:{data['port']}"

    def on_expire(self):
        # logging.debug(f"移除ip,{self.proxy}")
        pass


def _remove(ip: IP):
    _queue.remove(ip)
    # logging.info(f"移除{ip.proxy}, 当前ip数量:{len(_queue)}")
    # logging.debug(f"移除ip, {ip.proxy}")
    # print(f"移除ip, {ip.proxy}")


def _parse(data):
    try:
        for ip in data:
            try:
                ip = IP(ip)
                _queue.append(ip)
            except ValueError:
                pass
    except Exception as e:
        logging.error(f"生成带你IP错误, data={data}, \n error={repr(e)}")


def _save():
    data = []
    for ip in _queue:
        data.append({
            'proxy': ip.proxy,
            'expire_time': ip.expire_time
        })
    with open(f"{_local_cache}", 'w') as f:
        json.dump(data, f, indent=4, separators=(',', ': '))


# 代理ip url 指针
_url_point = 0

# 正在请求
_is_reqeusting = False


def _request():
    global _url_point
    global _is_reqeusting
    if _is_reqeusting:
        return
    num = len(_urls)
    if num == 0:
        return
    if num >= _url_point + 1:
        url = _urls[_url_point]
        _url_point = _url_point + 1
    else:
        url = _urls[0]
        _url_point = 1
    _is_reqeusting = True
    resp = requests.get(url)
    _is_reqeusting = False
    # print(resp.status_code)
    status = resp.status_code
    if status != 200:
        logging.error(f"请求代理IP失败,status={status}")
        _urls.remove(url)
        return
    text = resp.text

    try:
        obj = json.loads(text)
    except Exception as e:
        logging.error(f"解析代理IP数据错误, erro={repr(e)}")
    code = obj['code']
    if code != 200 and code != 0:
        logging.error(f"代理IP返回数据错误,response={text}")
        _urls.remove(url)
        return
    data = obj['data']
    _parse(data)
    logging.info(f"请求代理IP, 当前IP: {len(_queue)}")
    _save()


def _load_ip():
    # text = '''
    #     {"code":200,"msg":"ok","data":[{"ip":"223.215.175.115","port":766,"expire_time":"2021-01-07 12:37:13","city":"\u6c60\u5dde","isp":"\u7535\u4fe1"},{"ip":"182.99.185.82","port":36410,"expire_time":"2021-01-07 12:55:12","city":"\u5409\u5b89","isp":"\u7535\u4fe1"},{"ip":"123.134.119.221","port":3617,"expire_time":"2021-01-07 12:37:16","city":"\u83b1\u829c","isp":"\u8054\u901a"},{"ip":"27.204.97.93","port":36410,"expire_time":"2021-01-07 12:52:51","city":"\u83b1\u829c","isp":"\u8054\u901a"},{"ip":"59.54.160.239","port":36410,"expire_time":"2021-01-07 12:53:39","city":"\u4e0a\u9976","isp":"\u7535\u4fe1"},{"ip":"114.97.201.1","port":766,"expire_time":"2021-01-07 12:50:37","city":"\u5408\u80a5","isp":"\u7535\u4fe1"},{"ip":"60.166.117.194","port":766,"expire_time":"2021-01-07 12:39:54","city":"\u5408\u80a5","isp":"\u7535\u4fe1"},{"ip":"180.125.238.235","port":36410,"expire_time":"2021-01-07 12:41:48","city":"\u5f90\u5dde","isp":"\u7535\u4fe1"},{"ip":"125.125.152.154","port":5412,"expire_time":"2021-01-07 12:46:22","city":"\u6e56\u5dde","isp":"\u7535\u4fe1"},{"ip":"114.97.140.170","port":3617,"expire_time":"2021-01-07 12:45:39","city":"\u5408\u80a5","isp":"\u7535\u4fe1"},{"ip":"106.87.84.84","port":36410,"expire_time":"2021-01-07 12:48:09","city":"\u91cd\u5e86","isp":"\u7535\u4fe1"},{"ip":"114.99.5.99","port":766,"expire_time":"2021-01-07 12:39:28","city":"\u94dc\u9675","isp":"\u7535\u4fe1"},{"ip":"60.169.242.133","port":36410,"expire_time":"2021-01-07 12:46:52","city":"\u829c\u6e56","isp":"\u7535\u4fe1"},{"ip":"117.91.164.50","port":5412,"expire_time":"2021-01-07 12:46:14","city":"\u626c\u5dde","isp":"\u7535\u4fe1"},{"ip":"125.86.166.241","port":5412,"expire_time":"2021-01-07 13:03:33","city":"\u91cd\u5e86","isp":"\u7535\u4fe1"},{"ip":"114.97.200.106","port":766,"expire_time":"2021-01-07 12:40:53","city":"\u5408\u80a5","isp":"\u7535\u4fe1"},{"ip":"117.44.26.232","port":5412,"expire_time":"2021-01-07 12:55:26","city":"\u8d63\u5dde","isp":"\u7535\u4fe1"},{"ip":"114.106.134.220","port":3617,"expire_time":"2021-01-07 12:37:22","city":"\u6c60\u5dde","isp":"\u7535\u4fe1"},{"ip":"117.67.244.220","port":894,"expire_time":"2021-01-07 12:55:12","city":"\u5408\u80a5","isp":"\u7535\u4fe1"},{"ip":"123.134.78.129","port":3617,"expire_time":"2021-01-07 12:57:37","city":"\u83b1\u829c","isp":"\u8054\u901a"}]}
    #  '''
    try:
        with open(f"{_local_cache}", 'r') as f:
            text = f.read()
        data = json.loads(text)
    except:
        data = None
    if data:
        _parse(data)
    length = len(_queue)
    logging.info(f"本地缓存代理IP数量 = {length}")
    if length < _ip_min_num:
        _request()


def remove(ip: str):
    if not isinstance(ip, str):
        return
    for each in _queue:
        if each.proxy == ip:
            _remove(each)
            if len(_queue) < _ip_min_num:
                _request()
            break



# ip列表指针
_point = 0


def get():
    '''
    读取一个IP
    :return: proxy
    '''
    global _point
    num = len(_queue)
    if num > 0:
        if num > _point + 1:
            ip = _queue[_point]
            _point = _point + 1
        else:
            _point = 0
            return None
        return ip.proxy
    return None


def size():
    '''
    IP池剩余IP数量
    :return: int
    '''
    return len(_queue)


def close():
    global _ct
    global _init
    if _init:
        _ct.cancel()
        logging.info('ippool 关闭')
        _init = False
        _save()


_init = False


# 中心定时器
def init():
    global _ct
    global _init
    if not _init:
        logging.info('ippool 启动')
        _load_ip()
        _ct.start()
        _init = True
